package com.jddup.program.servlet;

import com.jddup.common.pojo.EntityAndDbDifference;
import com.jddup.common.pojo.TableColumn;
import com.jddup.common.pojo.TableMeta;
import com.jddup.common.pojo.vo.*;
import com.jddup.context.CompareContext;
import com.jddup.context.EntityTableMetaContext;
import com.jddup.context.JddConfigContext;
import com.jddup.program.comparator.CompatibilityStartup;
import com.jddup.program.utils.LinkMapCollectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;

/**
 * Created by ZZB on 2017/12/18.
 */
public class JddupService {
    private static final Logger logger = LoggerFactory.getLogger(JddupService.class);

    public BaseResponse<List<DataSourceIndexVO>> datasourceIndex(String key) {
        try {
            new CompatibilityStartup().startCompare();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        List<DataSourceIndexVO> list = buildDataSourceIndexVO();
        CompareContext.setDataSourceIndexVOS(list);
        return new BaseResponse<>(BaseResponse.SUCCESS, "", CompareContext.getDataSourceIndexVOS());
    }

    public BaseResponse<Map<String, ColumnDiffIndexVO>> columnDiffVO(String tableName, String columnName) {
        ColumnDiffIndexVO columnDiffIndexVO = CompareContext.getTableColumnDiffIndexVOMap().get(tableName).get(columnName);
        Map<String, ColumnDiffIndexVO> resultMap = new LinkedHashMap<>();
        if (columnDiffIndexVO != null) {
            resultMap.put(columnName, columnDiffIndexVO);
            if (columnDiffIndexVO.isDiff()) {
                return new BaseResponse<>(BaseResponse.NOT_SAME, "获取ColumnDiffVO成功", resultMap);
            }
            return new BaseResponse<>(BaseResponse.SUCCESS, "获取ColumnDiffVO成功", resultMap);
        }
        return new BaseResponse<>(BaseResponse.SUCCESS, "获取ColumnDiffVO成功");
    }

    public BaseResponse<Map<String, ColumnDiffIndexVO>> tableColumnDiffVO(String tableName) {

        Map<String, ColumnDiffIndexVO> map = CompareContext.getTableColumnDiffIndexVOMap().get(tableName);
        Map<String, ColumnDiffIndexVO> resultMap = new LinkedHashMap<>();
        Set<String> keySet = map.keySet();
        boolean isDiff = false;
        for (String key : keySet) {
            ColumnDiffIndexVO columnDiffIndexVO = map.get(key);
            if (columnDiffIndexVO.isDiff()) {
                resultMap.put(key, columnDiffIndexVO);
                isDiff = true;
            }
        }
        if (isDiff) {
            return new BaseResponse<>(BaseResponse.NOT_SAME, "获取ColumnDiffVO成功", resultMap);
        } else {
            return new BaseResponse<>(BaseResponse.SUCCESS, "获取ColumnDiffVO成功", resultMap);
        }
    }

    public BaseResponse executeSQL(String tableName, String columnName, String sql) {
        return null;
    }

    public BaseResponse executeCreateSQL(String tableName) {
        EntityAndDbDifference entityAndDbDifference = CompareContext.getTableNameDifferencesMap().get(tableName);
        String createTableDdl = entityAndDbDifference.getCreateTableDdl();
        String dbName = EntityTableMetaContext.getTableDataSourceMap().get(tableName);
        DataSource dataSource = JddConfigContext.getDataSourceMap().get(dbName);
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            Statement statement = connection.createStatement();
            statement.execute(createTableDdl);
        } catch (SQLException e) {
            return new BaseResponse(BaseResponse.SERVICE_EXCEPTION, "建表语句执行失败！" + e.getMessage());
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return new BaseResponse(BaseResponse.SUCCESS, "建表语句执行成功");
    }

    private List<DataSourceIndexVO> buildDataSourceIndexVO() {
        List<DataSourceIndexVO> list = new ArrayList<>();
        Map<String, DataSource> dataSourceMap = JddConfigContext.getDataSourceMap();
        for (String datasource : dataSourceMap.keySet()) {
            DataSourceIndexVO vo = new DataSourceIndexVO();
            vo.setDatasourceName(datasource);
            vo.setJdbcUrl(JddConfigContext.getDatasourceNameUrlMap().get(datasource));
            List<String> scanPackages = JddConfigContext.getDataSourceScanPackageMap().get(datasource);
            List<PackageIndexVO> packageIndexVOS = new ArrayList<>();
            for (String scanPackage : scanPackages) {
                PackageIndexVO packageIndexVO = new PackageIndexVO();
                packageIndexVO.setPackageName(scanPackage);
                List<TableIndexVO> tableIndexVOS = new ArrayList<>();
                List<Class> classes = JddConfigContext.getScanPackageEntityMap().get(scanPackage);
                for (Class aClass : classes) {
                    TableIndexVO tableIndexVO = new TableIndexVO();
                    TableMeta beanTableMeta = EntityTableMetaContext.getEntityTableMetaMap().get(aClass.getName());
                    TableMeta dbTableMeta = EntityTableMetaContext.getDbTableMetaMap().get(beanTableMeta.getTableName());
                    tableIndexVO.setBeanName(beanTableMeta.getBeanName());
                    tableIndexVO.setFullBeanName(beanTableMeta.getBeanClass().getName());
                    tableIndexVO.setTableName(beanTableMeta.getTableName());
                    tableIndexVO.setTableExist(dbTableMeta.getTableExist());
                    tableIndexVO.setColumnDiffIndexVOS(buildDiffIndexVO(beanTableMeta, dbTableMeta));
                    tableIndexVO.setCreateTableSql(CompareContext.getBeanNameDifferencesMap().get(beanTableMeta.getBeanName()).getCreateTableDdl());
                    tableIndexVO.setSuccessCount(new Long(tableIndexVO.getColumnDiffIndexVOS().stream().filter(columnDiffIndexVO -> columnDiffIndexVO.getLevel() == 1).count()).intValue());
                    tableIndexVO.setWarnningCount(new Long(tableIndexVO.getColumnDiffIndexVOS().stream().filter(columnDiffIndexVO -> columnDiffIndexVO.getLevel() == 2).count()).intValue());
                    tableIndexVO.setErrorCount(new Long(tableIndexVO.getColumnDiffIndexVOS().stream().filter(columnDiffIndexVO -> columnDiffIndexVO.getLevel() == 3).count()).intValue());
                    tableIndexVOS.add(tableIndexVO);
                }
                packageIndexVO.setTableIndexVOS(tableIndexVOS);
                packageIndexVOS.add(packageIndexVO);
            }
            vo.setPackageIndexVOS(packageIndexVOS);
            list.add(vo);
        }
        return list;
    }

    private List<ColumnDiffIndexVO> buildDiffIndexVO(TableMeta entity, TableMeta db) {
        CompareContext.getTableColumnDiffIndexVOMap().put(entity.getTableName(), new LinkedHashMap<>());

        List<ColumnDiffIndexVO> list = new ArrayList<>();
        Map<String, TableColumn> entityColumnMap = entity.getTableColumns().stream().collect(LinkMapCollectors.toMap(o -> o.getColumnName().toLowerCase(), o -> o));
        Map<String, TableColumn> dbColumnMap = new HashMap<>();
        if (db != null) {
            dbColumnMap.putAll(db.getTableColumns().stream().collect(LinkMapCollectors.toMap(o -> o.getColumnName().toLowerCase(), o -> o)));
        }
        //2.1 检查entity中有，但是db中没有的
        entityColumnMap.forEach((s, tableColumn) -> {
            ColumnDiffIndexVO columnDiffIndexVO = new ColumnDiffIndexVO();
            columnDiffIndexVO.setPropertyName(tableColumn.getPropertyName());
            columnDiffIndexVO.setPropertyType(tableColumn.getPropertyType().getTypeName());
            columnDiffIndexVO.setRecommendColumnType(tableColumn.getTypeFullName());
            EntityAndDbDifference.ModifyDDL modifyDDL = CompareContext.getBeanNameDifferencesMap().get(entity.getBeanName()).getDiffMap().get(tableColumn.getColumnName());
            columnDiffIndexVO.setModifyDDL(modifyDDL);
            if (modifyDDL != null) {
                if (modifyDDL.getLevel().equals(EntityAndDbDifference.ModifyDDL.LevelEnums.serious)) {
                    columnDiffIndexVO.setLevel(3);
                } else {
                    columnDiffIndexVO.setLevel(2);
                }
            } else {
                columnDiffIndexVO.setLevel(1);
            }
            if (dbColumnMap.containsKey(s)) {
                TableColumn dbColumn = dbColumnMap.get(s);
                columnDiffIndexVO.setColumnName(dbColumn.getColumnName());
                columnDiffIndexVO.setColumnType(dbColumn.getTypeFullName());
            }
            CompareContext.getTableColumnDiffIndexVOMap().get(entity.getTableName()).put(tableColumn.getColumnName(), columnDiffIndexVO);
            list.add(columnDiffIndexVO);
        });
        //2.2 检查entity中没有有，但是Db中有的
        dbColumnMap.forEach((s, tableColumn) -> {
            if (!entityColumnMap.containsKey(s)) {
                ColumnDiffIndexVO columnDiffIndexVO = new ColumnDiffIndexVO();
                columnDiffIndexVO.setColumnName(tableColumn.getColumnName());
                columnDiffIndexVO.setLevel(3);
                columnDiffIndexVO.setColumnType(tableColumn.getTypeFullName());
                EntityAndDbDifference.ModifyDDL modifyDDL = CompareContext.getBeanNameDifferencesMap().get(entity.getBeanName()).getDiffMap().get(tableColumn.getColumnName());
                columnDiffIndexVO.setModifyDDL(modifyDDL);
                CompareContext.getTableColumnDiffIndexVOMap().get(entity.getTableName()).put(tableColumn.getColumnName(), columnDiffIndexVO);
                list.add(columnDiffIndexVO);
            }
        });
        return list;
    }
}
